/**
 ******************************************************************************
 * @file file_operation.c
 * @author GX (2524913364@qq.com)
 * @brief 
 * @version 1.0.1
 * @date 2022-07-05
 * 
 * @copyright Copyright (c) 2022
 * 
 ******************************************************************************
 *----------------------------------------------------------------------------*
 *  Remark         : Description                                              *
 *----------------------------------------------------------------------------*
 *  Change History :                                                          *
 *  <Date>     | <Version> | <Author>       | <Description>                   *
 *----------------------------------------------------------------------------*
 *  2022-07-05 | 1.0.0     | GX             | Create file                     *
 *----------------------------------------------------------------------------*
 *  2022-07-06 | 1.0.0     | GX             | updata   f_size()               *
 *             |           |                | add      f_copy()               *
 *----------------------------------------------------------------------------*                                                                          *
 ******************************************************************************
 */


/*----------------------------- start of file -------------------------------*/
#include "file_operation.h"
 




/**
 * @brief  将原目录字符串裁剪成上级目录字符串
 *       如果正常变成上一级目录则会将新的目录保存到 *fPathPos
 *       如果路径已经是根目录或者格式不对就不会操作
 * 
 * @param fPathPos  处理结果由这个指针
 * @param path      需要处理的路径
 * @return true     成功
 * @return false    失败
 */
bool fatherPath(char *fPathPos, const char *path)
{
    /*检查代码段*/
    // {
    //     if(fPathPos == NULL)
    //     {
    //         return false;
    //     }

    //     if(!checkDir(path))
    //     {
    //         return false;
    //     }
    // }

    /*主要代码段*/
    int dirLV = 0;  //目录级

    /*保存源目录上级目录的缓存*/
    char *fPathBuff = malloc(strlen(path));
    char *pos = fPathBuff;

    /*将原目录字符串裁剪成上级目录字符串*/
    while(*path != '\0')
    {
        /*每一级目录字符串的缓存*/
        int i = 0;
        char buff[BUFFLEN];
        do
        {  
            buff[i] = *path;
            if((*path == '/') && (i != 0)) 
            {
                buff[i] = '\0'; 
                break;
            }

            i++; path++;
            /*检查 buff 的大小是否足够*/
            if(i == BUFFLEN-1)
            {
                printf("In file file_eof.c function fatherPath:need a bigger bufflen\n");
                printf("Will stop the operate\n");
                return false;
            }
        }
        while((i < BUFFLEN-1) && (*path != '\0'));
        
        /*如果这级不是最后一级则添加到缓存 fPathBuff 中*/
        if(*path != '\0')
        {
            for(int i = 0; buff[i] != '\0'; i++, pos++)
            {
                *pos = buff[i];
            }
            *pos = '\0';

            dirLV++;
        }   
        
    }

    /*原目录的上级是根目录则补多一个 '\'*/
    if(dirLV == 1)
    {
        printf("is root\n");
        *pos = '/';
        pos++;
        pos = '\0';
    }

    /*一切操作正常后将缓存中的路径全部打包到fPathPos中*/
    memcpy(fPathPos, fPathBuff, strlen(fPathBuff));

    return true;
}


/**
 * @brief   检查路径是否正常
 *        '/'后面紧跟'\0' 则为根目录
 *        '/'后面紧跟其它字符 则至少是两级目录
 *        没有'/'则为格式不正确的目录
 * 
 * @param path      需要检查的路径
 * @return true     成功
 * @return false    失败
 */
// bool checkDir(const char *path)
// {
//     /*数'/'的个数*/
//     for(int i = 0; path[i] != '\0'; i++)
//     {
//         if(path[i] == '/')
//         {
//             /*'/'后面紧跟'\0' 则为根目录*/
//             if(path[i+1] == '\0')
//             {
//                 printf("this a root directory!\n");
//                 return false;
//             }
//             /*至少是两级目录*/
//             else
//             {
//                 return true;
//             }
//         }
//     }

//     /*目录中没有'/'不是正常目录格式*/
//     printf("this a error directory!\n");
//     return false;

// }

/**
 * @brief 获取文件大小(字节)
 * 
 * @param fp 文件指针
 * @return long 成功返回文件大小字节数，失败返回-1
 */
long f_size(FILE *fp)
{
    struct stat fileInfo;
    int ret = fstat(fp->_fileno, &fileInfo);
    if(ret == -1)
    {
        perror("In function:f_size()\n stat error");
        return -1;
    }
    if( S_ISREG(fileInfo.st_mode) )
    {
        return fileInfo.st_size;
    }
    else
    {
        printf("This isn't a regular file\n");
        return -1;
    }
    
}

/**
 * @brief 复制文件，文件名要包含路径，可以是绝对路径或者相对路径
 * 
 * @param dstPath 目标文件名
 * @param srcPath 源文件名
 * @return true     复制成功
 * @return false    复制失败
 */
bool f_copy(const char *dstPath, const char *srcPath)
{
    printf("dst:%s\n", dstPath);
    printf("src:%s\n", srcPath);
  
    //2、打开源文件，以可读的方式打开
	FILE *srcFd = fopen(srcPath, "rb");
	if(srcFd == NULL)
    {
		perror("open src file error");
		return false;
	}
	//3、打开目标文件，以可写的方式，如果文件不存在则创建，如果存在则清空
	FILE *dstFd = fopen(dstPath, "wb");
	if(dstFd == NULL){
		perror("open dest file error");
		return false;
	}
	
	int srcFileSize = f_size(srcFd);/* 获取源文件大小 */    
    int r_block = 0;                  /* 读取的数据块数 */
    int w_block = 0;                  /* 已成功写入的数据块数 */
    int w_last = 0;                   /* 最后一次写入的数据量 */
    int pos1 = 0;                   /* 当前文件光标距离开头的字节数(用来处理最后一次复制) */
	
	int startTime = time(NULL);     /* 记录开始时间 */
    int endTime;                    /* 结束时间 */
	
    
	char *buf = calloc(COPY_BLOCK_NUM, COPY_BLOCK_BYTE);    /* 数据缓存 */
	
    while(1)
    {
        /* 记录当前文件的光标位置 */
        pos1 = ftell(srcFd);

        /* 读取数据 */
        r_block = fread(buf, COPY_BLOCK_BYTE, COPY_BLOCK_NUM,srcFd);

        /* 处理最后一次复制 */
        if( r_block = COPY_BLOCK_NUM )
        {
            /* 读取完 */
            if ( feof(srcFd) != 0 )
            {
                int pos2 = ftell(srcFd);
                /* 还要读取最后一次 */
                w_last = fwrite(buf, (pos2-pos1), 1, dstFd);
                printf("lsat:%d\n", w_last);
                printf("源文件大小:%0.3fM\t已复制大小:%0.3fM\t进度:%0.2f%%\n", BYTE_TO_M(srcFileSize),
                    BYTE_TO_M((w_block*COPY_BLOCK_BYTE) + (w_last*(pos2-pos1))), 
                    BYTE_TO_M((w_block*COPY_BLOCK_BYTE) + (w_last*(pos2-pos1)))/BYTE_TO_M(srcFileSize)*100);
                printf("copy end\n");
                break;
            }
            
            /* 出错 */
            if( ferror(srcFd) != 0 )
            {
                printf("read src error\n");
                break;
            }
        }

        /* 写入数据 */
        w_block += fwrite(buf, COPY_BLOCK_BYTE, COPY_BLOCK_NUM, dstFd);

        printf("源文件大小:%0.3fM\t已复制大小:%0.3fM\t进度:%0.2f%%\n", BYTE_TO_M(srcFileSize),
                    BYTE_TO_M(w_block*COPY_BLOCK_BYTE), w_block*COPY_BLOCK_BYTE*1.0/srcFileSize*100);
    }


    if(f_size(dstFd) != srcFileSize)
    {
        char path[100];
        sprintf(path, "rm %s", dstPath);
        printf("复制失败，将删除文件 %s\n", dstPath);
        system(path);
        return false;
    }

	//结束的时间
	endTime = time(NULL);
	printf("用时约%d秒\n",endTime-startTime);
	
	//6、关闭源文件 和 目标 文件
	fclose(srcFd);
	fclose(dstFd);
	
	free(buf);

    return true;
}





/*------------------------------ end of file --------------------------------*/

